import base64
import hashlib
import hmac
import json
import time
from datetime import datetime, timezone
import os
import uuid
from typing import Optional, Tuple, List
import wave
import opuslib_next

import requests
from core.providers.asr.base import ASRProviderBase
from config.logger import setup_logging

TAG = __name__
logger = setup_logging()

class ASRProvider(ASRProviderBase):
    API_URL = "https://asr.tencentcloudapi.com"
    API_VERSION = "2019-06-14"
    FORMAT = "pcm"  # 支持的音频格式：pcm, wav, mp3

    def __init__(self, config: dict, delete_audio_file: bool = True):
        self.secret_id = config.get("secret_id")
        self.secret_key = config.get("secret_key")
        self.output_dir = config.get("output_dir")
        
        # 确保输出目录存在
        os.makedirs(self.output_dir, exist_ok=True)

    def save_audio_to_file(self, opus_data: List[bytes], session_id: str) -> str:
        """PCM数据保存为WAV文件"""

        file_name = f"tencent_asr_{session_id}_{uuid.uuid4()}.wav"
        file_path = os.path.join(self.output_dir, file_name)
        
        with wave.open(file_path, "wb") as wf:
            wf.setnchannels(1)
            wf.setsampwidth(2)  # 2 bytes = 16-bit
            wf.setframerate(16000)
            wf.writeframes(b"".join(pcm_data))
        
        return file_path

    @staticmethod
    def decode_opus(opus_data: List[bytes]) -> bytes:
        """将Opus音频数据解码为PCM数据"""
        import opuslib_next
        
        decoder = opuslib_next.Decoder(16000, 1)  # 16kHz, 单声道
        pcm_data = []
        
        for opus_packet in opus_data:
            try:
                pcm_frame = decoder.decode(opus_packet, 960)  # 960 samples = 60ms
                pcm_data.append(pcm_frame)
            except opuslib_next.OpusError as e:
                logger.bind(tag=TAG).error(f"Opus解码错误: {e}", exc_info=True)
        
        return b"".join(pcm_data)

    async def speech_to_text(self, opus_data: List[bytes], session_id: str) -> Tuple[Optional[str], Optional[str]]:
        """将语音数据转换为文本"""
        if not opus_data:
            logger.bind(tag=TAG).warn("音频数据为空！")
            return None, None

        try:
            # 检查配置是否已设置
            if not self.secret_id or not self.secret_key:
                logger.bind(tag=TAG).error("腾讯云语音识别配置未设置，无法进行识别")
                return None, None

            # 将Opus音频数据解码为PCM
            pcm_data = self.decode_opus(opus_data)

            # 判断是否保存为WAV文件
            if self.delete_audio_file:
                pass
            else:
                self.save_audio_to_file(pcm_data, session_id)
            
            # 将音频数据转换为Base64编码
            base64_audio = base64.b64encode(pcm_data).decode('utf-8')

            # 构建请求体
            request_body = self._build_request_body(base64_audio)

            # 获取认证头
            timestamp, authorization = self._get_auth_headers(request_body)

            # 发送请求
            start_time = time.time()
            result = self._send_request(request_body, timestamp, authorization)
            
            if result:
                logger.bind(tag=TAG).debug(f"腾讯云语音识别耗时: {time.time() - start_time:.3f}s | 结果: {result}")
            
            return result, None

        except Exception as e:
            logger.bind(tag=TAG).error(f"处理音频时发生错误！{e}", exc_info=True)
            return None, None

    def _build_request_body(self, base64_audio: str) -> str:
        """构建请求体"""
        request_map = {
            "ProjectId": 0,
            "SubServiceType": 2,  # 一句话识别
            "EngSerViceType": "16k_zh",  # 中文普通话通用
            "SourceType": 1,  # 音频数据来源为语音文件
            "VoiceFormat": self.FORMAT,  # 音频格式
            "Data": base64_audio,  # Base64编码的音频数据
            "DataLen": len(base64_audio)  # 数据长度
        }
        return json.dumps(request_map)

    def _get_auth_headers(self, request_body: str) -> Tuple[str, str]:
        """获取认证头"""
        try:
            # 获取当前UTC时间戳
            now = datetime.now(timezone.utc)
            timestamp = str(int(now.timestamp()))
            date = now.strftime("%Y-%m-%d")

            # 服务名称必须是 "asr"
            service = "asr"

            # 拼接凭证范围
            credential_scope = f"{date}/{service}/tc3_request"

            # 使用TC3-HMAC-SHA256签名方法
            algorithm = "TC3-HMAC-SHA256"

            # 构建规范请求字符串
            http_request_method = "POST"
            canonical_uri = "/"
            canonical_query_string = ""

            # 注意：头部信息需要按照ASCII升序排列，且key和value都转为小写
            # 必须包含content-type和host头部
            content_type = "application/json; charset=utf-8"
            host = "asr.tencentcloudapi.com"
            action = "SentenceRecognition"  # 接口名称

            # 构建规范头部信息，注意顺序和格式
            canonical_headers = f"content-type:{content_type.lower()}\n" + \
                               f"host:{host.lower()}\n" + \
                               f"x-tc-action:{action.lower()}\n"

            signed_headers = "content-type;host;x-tc-action"

            # 请求体哈希值
            payload_hash = self._sha256_hex(request_body)

            # 构建规范请求字符串
            canonical_request = f"{http_request_method}\n" + \
                               f"{canonical_uri}\n" + \
                               f"{canonical_query_string}\n" + \
                               f"{canonical_headers}\n" + \
                               f"{signed_headers}\n" + \
                               f"{payload_hash}"

            # 计算规范请求的哈希值
            hashed_canonical_request = self._sha256_hex(canonical_request)

            # 构建待签名字符串
            string_to_sign = f"{algorithm}\n" + \
                            f"{timestamp}\n" + \
                            f"{credential_scope}\n" + \
                            f"{hashed_canonical_request}"

            # 计算签名密钥
            secret_date = self._hmac_sha256(f"TC3{self.secret_key}", date)
            secret_service = self._hmac_sha256(secret_date, service)
            secret_signing = self._hmac_sha256(secret_service, "tc3_request")

            # 计算签名
            signature = self._bytes_to_hex(self._hmac_sha256(secret_signing, string_to_sign))

            # 构建授权头
            authorization = f"{algorithm} " + \
                           f"Credential={self.secret_id}/{credential_scope}, " + \
                           f"SignedHeaders={signed_headers}, " + \
                           f"Signature={signature}"

            return timestamp, authorization

        except Exception as e:
            logger.bind(tag=TAG).error(f"生成认证头失败: {e}", exc_info=True)
            raise RuntimeError(f"生成认证头失败: {e}")

    def _send_request(self, request_body: str, timestamp: str, authorization: str) -> Optional[str]:
        """发送请求到腾讯云API"""
        headers = {
            "Content-Type": "application/json; charset=utf-8",
            "Host": "asr.tencentcloudapi.com",
            "Authorization": authorization,
            "X-TC-Action": "SentenceRecognition",
            "X-TC-Version": self.API_VERSION,
            "X-TC-Timestamp": timestamp,
            "X-TC-Region": "ap-shanghai"
        }

        try:
            response = requests.post(self.API_URL, headers=headers, data=request_body)
            
            if not response.ok:
                raise IOError(f"请求失败: {response.status_code} {response.reason}")
            
            response_json = response.json()
            
            # 检查是否有错误
            if "Response" in response_json and "Error" in response_json["Response"]:
                error = response_json["Response"]["Error"]
                error_code = error["Code"]
                error_message = error["Message"]
                raise IOError(f"API返回错误: {error_code}: {error_message}")
            
            # 提取识别结果
            if "Response" in response_json and "Result" in response_json["Response"]:
                return response_json["Response"]["Result"]
            else:
                logger.bind(tag=TAG).warn(f"响应中没有识别结果: {response_json}")
                return ""
                
        except Exception as e:
            logger.bind(tag=TAG).error(f"发送请求失败: {e}", exc_info=True)
            return None

    def _sha256_hex(self, data: str) -> str:
        """计算字符串的SHA256哈希值"""
        digest = hashlib.sha256(data.encode('utf-8')).digest()
        return self._bytes_to_hex(digest)

    def _hmac_sha256(self, key, data: str) -> bytes:
        """计算HMAC-SHA256"""
        if isinstance(key, str):
            key = key.encode('utf-8')
        
        return hmac.new(key, data.encode('utf-8'), hashlib.sha256).digest()

    def _bytes_to_hex(self, bytes_data: bytes) -> str:
        """字节数组转十六进制字符串"""
        return ''.join(f"{b:02x}" for b in bytes_data)